<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AI聊天接口测试</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }

    body {
      background-color: #f5f7fa;
      color: #333;
      line-height: 1.6;
      padding: 20px;
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
      background: white;
      border-radius: 10px;
      box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
      overflow: hidden;
    }

    header {
      background: linear-gradient(135deg, #3494e6, #ec6ead);
      color: white;
      padding: 20px;
      text-align: center;
    }

    h1 {
      font-size: 1.5rem;
      margin-bottom: 10px;
    }

    .api-info {
      font-size: 0.9rem;
      margin-top: 5px;
    }

    .chat-container {
      padding: 20px;
      height: 400px;
      overflow-y: auto;
      background: #f8f9fa;
    }

    .message {
      margin-bottom: 15px;
      padding: 12px 15px;
      border-radius: 8px;
      max-width: 85%;
      animation: fadeIn 0.3s;
    }

    .user-message {
      background: #e3f2fd;
      margin-left: auto;
    }

    .ai-message {
      background: #f1f8e9;
      margin-right: auto;
    }

    .input-area {
      padding: 15px 20px;
      border-top: 1px solid #eee;
      background: white;
    }

    .input-group {
      display: flex;
      gap: 10px;
    }

    input {
      flex: 1;
      padding: 12px 15px;
      border: 1px solid #ddd;
      border-radius: 5px;
      font-size: 1rem;
    }

    button {
      background: #3494e6;
      color: white;
      border: none;
      padding: 12px 20px;
      border-radius: 5px;
      cursor: pointer;
      font-weight: 600;
      transition: background 0.3s;
    }

    button:hover {
      background: #2980b9;
    }

    .status {
      margin-top: 10px;
      font-size: 0.9rem;
      color: #666;
      display: flex;
      align-items: center;
    }

    .status-indicator {
      display: inline-block;
      width: 10px;
      height: 10px;
      border-radius: 50%;
      margin-right: 8px;
    }

    .online {
      background: #2ecc71;
    }

    .offline {
      background: #e74c3c;
    }

    .typing {
      display: inline-block;
      margin-left: 10px;
    }

    .typing span {
      animation: bounce 1.5s infinite;
      display: inline-block;
      height: 8px;
      width: 8px;
      background: #666;
      border-radius: 50%;
      margin: 0 2px;
    }

    .typing span:nth-child(2) {
      animation-delay: 0.2s;
    }

    .typing span:nth-child(3) {
      animation-delay: 0.4s;
    }

    @keyframes fadeIn {
      from {
        opacity: 0;
        transform: translateY(10px);
      }

      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    @keyframes bounce {

      0%,
      100% {
        transform: translateY(0);
      }

      50% {
        transform: translateY(-5px);
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <header>
      <h1>AI聊天接口测试</h1>
      <div class="api-info">API端点: http://localhost:8090/api/v1/ollama/test</div>
    </header>

    <div class="chat-container" id="chatBox">
      <!-- 聊天消息将在这里显示 -->
    </div>

    <div class="input-area">
      <div class="input-group">
        <input type="text" id="messageInput" placeholder="输入消息..." autocomplete="off">
        <button id="sendButton">发送</button>
      </div>

      <div class="status">
        <span class="status-indicator online"></span>
        <span id="statusText">API状态: 在线</span>
        <span class="typing" id="typingIndicator" style="display:none">
          <span></span>
          <span></span>
          <span></span>
        </span>
      </div>
    </div>
  </div>

  <script>
    // DOM元素
    const chatBox = document.getElementById('chatBox');
    const messageInput = document.getElementById('messageInput');
    const sendButton = document.getElementById('sendButton');
    const statusText = document.getElementById('statusText');
    const typingIndicator = document.getElementById('typingIndicator');

    // 当前状态
    let isStreaming = false;
    let currentResponse = null;

    // 发送按钮点击事件
    sendButton.addEventListener('click', sendMessage);

    // 回车键发送消息
    messageInput.addEventListener('keypress', function (e) {
      if (e.key === 'Enter') {
        sendMessage();
      }
    });

    // 发送消息函数
    function sendMessage() {
      const message = messageInput.value.trim();
      if (!message || isStreaming) return;

      // 重置状态
      isStreaming = true;
      messageInput.value = '';
      typingIndicator.style.display = 'inline-block';
      statusText.textContent = 'API状态: 流式响应中...';

      // 在聊天框中显示用户消息
      addMessage('user', message);

      // 创建AI消息容器
      currentResponse = addMessage('ai', '');

      // 调用API
      fetch('http://localhost:8090/api/v1/ollama/test', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          message: message,
          re_chat: false,
          stream: true
        })
      })
        .then(response => {
          if (!response.ok) {
            throw new Error(`API错误: ${response.status}`);
          }

          // 创建读取器处理流式响应
          const reader = response.body.getReader();
          const decoder = new TextDecoder();
          let buffer = '';

          // 递归读取流
          function readStream() {
            return reader.read().then(({ value, done }) => {
              if (done) {
                isStreaming = false;
                typingIndicator.style.display = 'none';
                statusText.textContent = 'API状态: 完成';
                return;
              }

              // 解码数据块
              const chunk = decoder.decode(value, { stream: true });
              buffer += chunk;

              // 处理可能的多条消息
              const events = buffer.split('\n\n');
              buffer = events.pop() || ''; // 保存不完整的事件

              // 处理每个完整的事件
              events.forEach(event => {
                if (event.startsWith('data:')) {
                  const jsonStr = event.substring(5).trim();
                  try {
                    const data = JSON.parse(jsonStr);
                    processEvent(data);
                  } catch (e) {
                    console.error('解析JSON错误:', e);
                  }
                }
              });

              // 继续读取
              return readStream();
            });
          }

          return readStream();
        })
        .catch(error => {
          console.error('请求错误:', error);
          statusText.textContent = 'API状态: 离线';
          statusText.previousElementSibling.className = 'status-indicator offline';
          isStreaming = false;
          typingIndicator.style.display = 'none';

          if (currentResponse) {
            currentResponse.textContent = '请求出错: ' + error.message;
          }
        });
    }

    // 处理单个SSE事件
    function processEvent(data) {
      // 处理内容
      if (data.content) {
        // 解码Unicode字符
        const decodedContent = decodeUnicode(data.content);
        currentResponse.textContent += decodedContent;
      }

      // 滚动到最新消息
      chatBox.scrollTop = chatBox.scrollHeight;

      // 检查是否结束
      if (data.is_end) {
        isStreaming = false;
        typingIndicator.style.display = 'none';
        statusText.textContent = 'API状态: 完成';
      }
    }

    // 添加消息到聊天框
    function addMessage(type, text) {
      const messageDiv = document.createElement('div');
      messageDiv.className = `message ${type}-message`;
      messageDiv.textContent = text;
      chatBox.appendChild(messageDiv);
      chatBox.scrollTop = chatBox.scrollHeight;
      return messageDiv;
    }

    // 解码Unicode字符
    function decodeUnicode(str) {
      return str.replace(/\\u([\dA-F]{4})/gi,
        (match, grp) => String.fromCharCode(parseInt(grp, 16)));
    }

    // 初始化示例消息
    addMessage('ai', '你好！我是AI助手，有什么我可以帮您的吗？');
  </script>
</body>

</html>